import tkinter as tk
from tkinter import ttk
import time
import math
from PIL import Image, ImageTk
import threading

class ProgressOverlay:
    def __init__(self, parent, step_info):
        """
        进度覆盖层初始化
        
        参数:
            parent: 父窗口
            step_info: 步骤信息列表，每个元素为元组 (步骤名称, 持续时间)
        """
        self.parent = parent
        self.step_info = step_info
        self.steps = [info[0] for info in step_info]
        self.step_durations = [info[1] for info in step_info]
        self.total_time_sec = sum(self.step_durations)
        self.current_step = 0
        self.start_time = 0
        self.step_start_time = 0
        self.running = False
        self.create_progressbar_ui()#创建滚动条UI组件
                
    def create_progressbar_ui(self):
        """创建滚动条UI组件"""
        # 创建遮罩层
        self.overlay = tk.Toplevel(self.parent)
        self.overlay.title("")
        self.overlay.overrideredirect(True)  # 隐藏标题栏和边框
        self.overlay.attributes("-alpha", 1.0)  # 设置完全不透明
        self.overlay.configure(bg="#f0f0f0")  # 修改为浅灰色背景
        self.overlay.transient(self.parent)  # 保持模态关系
        self.overlay.withdraw()  # 初始隐藏
        self.overlay.protocol("WM_DELETE_WINDOW", self.safe_hide)# 添加窗口关闭事件处理
        # 添加窗口行为配置
        self.configure_window_behavior()
        
        # 添加边框装饰
        self.container = tk.Frame(self.overlay, 
                                 bg="white", 
                                 bd=2, 
                                 relief="groove")  # 添加边框效果
        self.container.place(relx=0.5, rely=0.5, anchor="center")
        
        # 进度标题
        self.title = tk.Label(
            self.container, 
            text="数据处理任务执行中，请稍候...",
            font=("Segoe UI", 16, "bold"),
            fg="#2c3e50",
            bg="white"
        )
        self.title.grid(row=0, column=0, pady=(20, 25), padx=30, sticky="ew")
        
        # 进度条容器
        progress_frame = tk.Frame(self.container, bg="white")
        progress_frame.grid(row=1, column=0, padx=30, pady=(0, 25), sticky="ew")
        
        # 进度条背景
        self.progress_bg = tk.Canvas(
            progress_frame, 
            height=32,
            bg="#e0e0e0",
            highlightthickness=0,
            borderwidth=0,
            relief="flat"
        )
        self.progress_bg.pack(fill="x")
        
        # 进度条前景
        self.progress_fg = tk.Canvas(
            self.progress_bg,
            height=32,
            bg="#3498db",
            highlightthickness=0,
            borderwidth=0,
            relief="flat"
        )
        self.progress_fg.place(x=0, y=0, width=0)  # 初始宽度为0
        
        # 百分比标签
        self.percent_label = tk.Label(
            self.progress_bg,
            text="0%",
            font=("Segoe UI", 11, "bold"),
            fg="#2c3e50"
        )
        self.percent_label.place(relx=0.5, rely=0.5, anchor="center")
        
        # 时间统计
        stats_frame = tk.Frame(self.container, bg="white")
        stats_frame.grid(row=2, column=0, padx=30, pady=(0, 25), sticky="ew")
        
        # 预估时间
        self.estimated_frame = tk.Frame(stats_frame, bg="#f8f9fa", relief="flat", padx=12, pady=12)
        self.estimated_frame.pack(side="left", fill="both", expand=True, padx=5)
        tk.Label(
            self.estimated_frame, 
            text="预估:", 
            font=("Segoe UI", 11), 
            bg="#f8f9fa", 
            fg="#555"
        ).pack(side="left")
        self.estimated_value = tk.Label(
            self.estimated_frame, 
            text=self.format_time(self.total_time_sec), 
            font=("Segoe UI", 11, "bold"), 
            bg="#f8f9fa", 
            fg="#555"
        )
        self.estimated_value.pack(side="left", padx=(5, 0))
        
        # 已执行时间
        self.elapsed_frame = tk.Frame(stats_frame, bg="#f8f9fa", relief="flat", padx=12, pady=12)
        self.elapsed_frame.pack(side="left", fill="both", expand=True, padx=5)
        tk.Label(
            self.elapsed_frame, 
            text="已执行:", 
            font=("Segoe UI", 11), 
            bg="#f8f9fa", 
            fg="#555"
        ).pack(side="left")
        self.elapsed_value = tk.Label(
            self.elapsed_frame, 
            text="0分0秒", 
            font=("Segoe UI", 11, "bold"), 
            bg="#f8f9fa", 
            fg="#555"
        )
        self.elapsed_value.pack(side="left", padx=(5, 0))
        
        # 剩余时间
        self.remaining_frame = tk.Frame(stats_frame, bg="#f8f9fa", relief="flat", padx=12, pady=12)
        self.remaining_frame.pack(side="left", fill="both", expand=True, padx=5)
        tk.Label(
            self.remaining_frame, 
            text="剩余:", 
            font=("Segoe UI", 11), 
            bg="#f8f9fa", 
            fg="#555"
        ).pack(side="left")
        self.remaining_value = tk.Label(
            self.remaining_frame, 
            text=self.format_time(self.total_time_sec), 
            font=("Segoe UI", 11, "bold"), 
            bg="#f8f9fa", 
            fg="#555"
        )
        self.remaining_value.pack(side="left", padx=(5, 0))
        
        # 步骤计数
        self.steps_count = tk.Label(
            self.container, 
            text=f"共{len(self.steps)}个步骤，当前正在执行第 0 步",
            font=("Segoe UI", 12),
            fg="#34495e",
            bg="white"
        )
        self.steps_count.grid(row=3, column=0, pady=(0, 15), padx=30, sticky="w")
        
        # 步骤列表容器
        steps_container = tk.Frame(self.container, bg="#f8f9fa", height=200)
        steps_container.grid(row=4, column=0, padx=30, pady=(0, 25), sticky="nsew")
        
        # 添加滚动条
        scrollbar = ttk.Scrollbar(steps_container)
        scrollbar.pack(side="right", fill="y")
        
        # 步骤列表画布
        self.steps_canvas = tk.Canvas(
            steps_container, 
            bg="#f8f9fa", 
            yscrollcommand=scrollbar.set,
            highlightthickness=0
        )
        self.steps_canvas.pack(side="left", fill="both", expand=True)
        scrollbar.config(command=self.steps_canvas.yview)
        
        # 步骤列表框架
        self.steps_frame = tk.Frame(self.steps_canvas, bg="#f8f9fa")
        self.steps_canvas.create_window((0, 0), window=self.steps_frame, anchor="nw")
        
        # 绑定配置事件
        self.steps_frame.bind("<Configure>", self.on_frame_configure)
        
        # 创建步骤项
        self.step_items = []
        max_duration_width = max(len(f"预计: {duration}秒") for duration in self.step_durations) + 10
        estimated_width = 420  # 60是左右padding的大致总和
        for i, step in enumerate(self.steps):
            # 整体容器
            frame = tk.Frame(self.steps_frame, bg="#f8f9fa", padx=0, pady=0,width=estimated_width)
            frame.pack(fill="x", pady=(0, 8))
            
            # 步骤状态
            status = tk.Frame(frame, bg="#9E9E9E", width=28, height=28)
            status.pack(side="left", padx=(10, 10))
            tk.Label(
                status, 
                text=str(i+1), 
                font=("Segoe UI", 10), 
                fg="white",  # 初始为白色文字
                bg="#9E9E9E"
            ).place(relx=0.5, rely=0.5, anchor="center")

            # 步骤文本和时间容器（整体容器）
            content_frame = tk.Frame(frame, bg="#f8f9fa", height=40)  # 统一高度
            content_frame.pack(side="left", fill="x", expand=True)

            # 步骤文本（左对齐）
            step_label = tk.Label(
                content_frame, 
                text=step, 
                font=("Segoe UI", 11), 
                fg="#616161",  # 初始灰色文字
                bg="#f8f9fa",
                anchor="w"
            )
            step_label.pack(side="left", fill="x", anchor="w", expand=True)

            # 步骤时间（右对齐）
            duration = self.step_durations[i]
            time_label = tk.Label(
                content_frame, 
                text=f"预计: {duration}秒", 
                font=("Segoe UI", 9), 
                fg="#9E9E9E",  # 初始灰色文字
                bg="#f8f9fa",
                anchor="e",
                width=max_duration_width
            )
            time_label.pack(side="right", padx=(0, 10))

            self.step_items.append({
                "frame": frame,
                "status": status,
                "text": step_label,
                "time": time_label,
                "status_label": status.winfo_children()[0]  # 保存状态标签引用
            })
    
    def recreate_ui(self):
        self.create_progressbar_ui()
        # 重置状态
        self.reset()

    def on_frame_configure(self, event):
        """更新画布滚动区域并设置步骤项宽度"""
        # 仅在有实际变化时更新
        current_width = self.steps_frame.winfo_width()
        canvas_width = self.steps_canvas.winfo_width()
        
        if current_width != canvas_width:  
            # 设置步骤框架的宽度
            self.steps_canvas.itemconfigure(
                self.steps_canvas.find_withtag("current"),  # 仅修改当前项目
                width=canvas_width
            )
            
            # 更新滚动区域
            self.steps_canvas.configure(scrollregion=self.steps_canvas.bbox("all"))
            
            # 强制更新布局
            self.steps_canvas.update_idletasks()
    
    def format_time(self, seconds):
        """将秒数格式化为分秒字符串"""
        minutes = int(seconds // 60)
        seconds = int(seconds % 60)
        return f"{minutes}分{seconds:02d}秒"
    
    def show(self):
        """显示遮罩层"""
        # 如果窗口已被销毁，重新创建所有UI组件
        if not self.overlay.winfo_exists():
            self.recreate_ui()

        # 更新为当前屏幕尺寸
        self.overlay.geometry(
            f"{self.parent.winfo_width()}x{self.parent.winfo_height()}+"
            f"{self.parent.winfo_x()}+{self.parent.winfo_y()}"
        )
        
        # 强制更新窗口状态
        self.overlay.update_idletasks()
        
        # 显示窗口并置顶
        self.overlay.deiconify()
        self.overlay.lift()  # 确保窗口置顶        
        
        # 重新计算容器位置
        self.container.place(relx=0.5, rely=0.5, anchor="center")
        
        # 启动进度更新（使用Tkinter事件循环）
        self.start_time = time.time()
        self.step_start_time = self.start_time  # 记录当前步骤开始时间
        self.running = True
        self.update_step_ui()
        self.update_progress()

    def safe_hide(self):
        """安全关闭窗口的处理方法"""
        self.running = False
        if self.overlay.winfo_exists():
            self.overlay.withdraw()

        # 解绑事件
        self.parent.unbind("<Configure>")
        self.parent.unbind("<FocusIn>")  
        self.parent.unbind("<Activate>")  
        self.overlay.unbind("<FocusIn>")
    
    def update_progress(self):
        """更新进度"""
        if not self.running:
            return
            
        now = time.time()
        # 计算当前步骤已用时间和总已用时间
        step_elapsed = now - self.step_start_time
        total_elapsed = now - self.start_time
        
        # 检查当前步骤是否有效且是否完成
        if self.current_step < len(self.steps) and step_elapsed >= self.step_durations[self.current_step]:
            # 移动到下一步
            self.current_step += 1
            
            # 如果所有步骤已完成，则完成任务
            if self.current_step >= len(self.steps):
                self.complete_task()
                return
                
            # 重置当前步骤开始时间
            self.step_start_time = now
            step_elapsed = 0
            
            # 更新步骤状态
            self.update_step_ui()
        
        # 计算整体进度（考虑各步骤不同耗时）
        completed_time = sum(self.step_durations[:self.current_step]) + step_elapsed
        progress = min(1.0, completed_time / self.total_time_sec)
        percent = int(progress * 100)
        
        # 更新进度条
        bg_width = self.progress_bg.winfo_width()
        if bg_width <= 1:
            bg_width = 400
        width = int(progress * bg_width)
        self.progress_fg.place(x=0, y=0, width=width)
        self.progress_fg.update_idletasks()
        
        # 更新百分比
        self.percent_label.config(text=f"{percent}%")
        
        # 更新时间
        self.elapsed_value.config(text=self.format_time(int(total_elapsed)))
        self.remaining_value.config(text=self.format_time(max(0, int(self.total_time_sec - total_elapsed))))
        
        # 每100毫秒更新一次
        self.overlay.after(100, self.update_progress)
        # 修改update_step_ui方法
    def update_step_ui(self):
        """更新步骤UI状态"""
        self.steps_count.config(text=f"共{len(self.steps)}个步骤，当前正在执行第 {self.current_step+1} 步")
        
        # 更新步骤状态
        for i, item in enumerate(self.step_items):
            if i < self.current_step:
                # 已完成步骤 - 绿色背景，白色文字
                item["frame"].config(bg="#E8F5E9")  # 浅绿色背景
                item["status"].config(bg="#4CAF50")  # 深绿色状态
                item["status_label"].config(text="✓", bg="#4CAF50", fg="white")
                item["text"].config(fg="#2E7D32", bg="#E8F5E9")  # 深绿色文字
                item["time"].config(fg="#2E7D32", bg="#E8F5E9")  # 深绿色文字
                item["text"].master.config(bg="#E8F5E9")  # 更新内容容器背景色
            elif i == self.current_step:
                # 当前步骤 - 蓝色背景，白色文字
                item["frame"].config(bg="#E3F2FD")  # 浅蓝色背景
                item["status"].config(bg="#2196F3")  # 深蓝色状态
                item["status_label"].config(text=str(i+1), bg="#2196F3", fg="white")
                item["text"].config(fg="#0D47A1", bg="#E3F2FD")  # 深蓝色文字
                item["time"].config(fg="#0D47A1", bg="#E3F2FD")  # 深蓝色文字
                item["text"].master.config(bg="#E3F2FD")  # 更新内容容器背景色
            else:
                # 未开始步骤 - 灰色背景，灰色文字
                item["frame"].config(bg="#f8f9fa")  # 浅灰色背景
                item["status"].config(bg="#9E9E9E")  # 深灰色状态
                item["status_label"].config(text=str(i+1), bg="#9E9E9E", fg="white")
                item["text"].config(fg="#616161", bg="#f8f9fa")  # 中灰色文字
                item["time"].config(fg="#9E9E9E", bg="#f8f9fa")  # 深灰色文字
                item["text"].master.config(bg="#f8f9fa")  # 更新内容容器背景色
    def complete_task(self):
        """任务完成处理"""
        # 更新为100%
        self.percent_label.config(text="100%")
        self.progress_fg.config(width=self.progress_bg.winfo_width())
        
        # 更新时间为总时间
        self.elapsed_value.config(text=self.format_time(self.total_time_sec))
        self.remaining_value.config(text=self.format_time(0))
        
        # 标记所有步骤为已完成
        self.steps_count.config(text=f"共{len(self.steps)}个步骤，任务已完成")
        
        for i, item in enumerate(self.step_items):
            item["status"].config(bg="#4CAF50")
            item["status"].winfo_children()[0].config(text="✓", bg="#4CAF50")
        
        # 2秒后关闭
        self.overlay.after(2000, self.safe_hide)
    def reset(self):
        """重置进度状态到初始值"""
        self.current_step = 0
        self.start_time = 0
        self.step_start_time = 0
        self.running = False
        
        # 检查窗口部件是否还存在
        if self.overlay.winfo_exists():
            # 重置UI状态
            self.progress_fg.place(x=0, y=0, width=0)
            self.percent_label.config(text="0%")
            self.elapsed_value.config(text="0分0秒")
            self.remaining_value.config(text=self.format_time(self.total_time_sec))
            self.steps_count.config(text=f"共{len(self.steps)}个步骤，当前正在执行第 0 步")
            
            # 重置步骤状态
            for i, item in enumerate(self.step_items):
                if item["status"].winfo_exists():  # 检查部件是否存在
                    item["frame"].config(bg="#f8f9fa")  # 重置背景色
                    item["status"].config(bg="#9E9E9E")  # 重置状态框颜色
                    item["status_label"].config(text=str(i+1), bg="#9E9E9E", fg="white")
                    item["text"].config(fg="#616161", bg="#f8f9fa")  # 重置文字颜色
                    item["time"].config(fg="#9E9E9E", bg="#f8f9fa")  # 重置时间颜色


    def configure_window_behavior(self):
        """
        配置窗口行为，确保覆盖层只在父窗口之上，不影响其他应用
        """
        # 确保覆盖层在父窗口之上
        self.overlay.lift(self.parent)
        
        # 绑定父窗口事件
        self.parent.bind("<Configure>", self._on_parent_configure)
        self.parent.bind("<FocusIn>", self._on_parent_activate)  
        self.parent.bind("<Activate>", self._on_parent_activate)  
        
        # 绑定覆盖层事件
        self.overlay.bind("<FocusIn>", self._on_focus_in)
        
    def _on_parent_configure(self, event):
        """当父窗口大小或位置变化时更新覆盖层"""
        if self.overlay.winfo_exists():
            self.overlay.geometry(
                f"{self.parent.winfo_width()}x{self.parent.winfo_height()}+"
                f"{self.parent.winfo_x()}+{self.parent.winfo_y()}"
            )
            self.container.place(relx=0.5, rely=0.5, anchor="center")

    def _on_focus_in(self, event):
        """当覆盖层获得焦点时，确保它保持在父窗口之上"""
        self.overlay.lift(self.parent)

    def _on_parent_activate(self, event):
        """当父窗口激活时，提升覆盖层到父窗口之上"""
        if self.overlay.winfo_exists() and self.overlay.winfo_viewable():
            self.overlay.lift(self.parent)
            self.container.place(relx=0.5, rely=0.5, anchor="center")

class MainApplication:
    def __init__(self, root):
        self.root = root
        self.root.title("应用程序主界面")
        self.root.geometry("800x500")
        self.root.configure(bg="#6a11cb")
        
        # 添加渐变背景
        self.canvas = tk.Canvas(root, bg="#6a11cb", highlightthickness=0)
        self.canvas.pack(fill="both", expand=True)
        
        # 创建内容区域
        self.content_frame = tk.Frame(self.canvas, bg="white", bd=0, highlightthickness=0)
        self.content_frame.place(relx=0.5, rely=0.5, anchor="center", width=700, height=300)
        
        # 添加标题
        title = tk.Label(
            self.content_frame, 
            text="应用程序主界面", 
            font=("Segoe UI", 22, "bold"), 
            fg="#2c3e50", 
            bg="white"
        )
        title.pack(pady=(30, 20))
        
        # 添加描述
        description = tk.Label(
            self.content_frame, 
            text="长时间任务执行时，此区域将被半透明遮罩覆盖，并在遮罩上显示带有进度百分比的可视化进度条。",
            font=("Segoe UI", 12),
            fg="#34495e",
            bg="white",
            wraplength=600
        )
        description.pack(pady=(0, 30), padx=30)
        
        # 添加开始按钮
        style = ttk.Style()
        style.configure("Start.TButton", 
                        font=("Segoe UI", 11, "bold"),
                        background="#3498db",
                        foreground="black",
                        borderwidth=0,
                        padding=10,
                        width=20)
        
        self.start_btn = ttk.Button(
            self.content_frame, 
            text="开始数据处理任务", 
            style="Start.TButton",
            command=self.start_task
        )
        self.start_btn.pack(pady=(0, 30))
        
        self.step_info = [
            ("初始化系统环境", 2),
            ("加载数据文件", 1),
            ("数据预处理", 2),
            ("特征工程处理", 3),
            ("模型训练", 20),
            ("模型验证", 1.5),
            ("结果分析", 6),
            ("生成报告", 3),
            ("数据存储", 2),
            ("清理临时文件", 1)
        ]
        
        # 创建进度遮罩
        self.progress_overlay = ProgressOverlay(root, self.step_info)
    
    def start_task(self):
        """开始任务"""
        # 禁用按钮防止重复点击
        self.start_btn.config(state="disabled")

        # 重置进度条状态
        self.progress_overlay.reset() 
        
        # 显示进度遮罩
        self.progress_overlay.show()
        
        # 任务完成后重新启用按钮
        self.root.after(12500, lambda: self.start_btn.config(state="normal"))

# 创建主窗口
if __name__ == "__main__":
    root = tk.Tk()
    app = MainApplication(root)
    root.mainloop()